﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using KC.DataAccess.MV6;
using KC.DataAccess.BuggerAll;
using KC.ExtensionMethods;

namespace KC.Business.Meta.Jobs
{
	public class DailyReportJob : JobBase 
	{
		protected override void PreProcess_Global()
		{
			dcMV6 = new DataAccess.MV6.MV6DataContext();
		}
		protected override void Process_Global()
		{
			string report = BuildDailyReport();
			Sendmail(report);
			base.UpdateResults("Daily report sent",false);
		}
		protected override void PostProcess_Global()
		{
		}

		#region Implementation

		/// <summary>Builds the Daily Report.</summary>
		/// <returns>Daily Report body as a string</returns>
		private string BuildDailyReport()
		{
			DateTime started = DateTime.Now;

			string TempReport = "";

			TempReport += GetSuggestedSearchStatuses();
			TempReport += GetErrors();
			TempReport += BuildListOfBrokenImgTags();

			return
				"Daily Report for " + DateTime.Now.ToString("MMM dd, yyyy") + "\r\n\r\n" +
				"Report started at " + started.ToString("MM/dd/yyyy HH:mm:ss") +
				"\r\nReport completed at " + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") +
				"\r\nReport ran for " + (DateTime.Now - started).ToString() + "\r\n\r\n" +
				TempReport;
		}
		/// <summary>Recommends a series of search queries to keep track of based on complex data heuristics</summary>
		/// <returns>recommended searchstatus values</returns>
		private string GetSuggestedSearchStatuses()
		{
			// Get popular search queries
			List<string>
				results = new List<string>(),
				results2 = new List<string>();

			DataTable dt = KC.DataAccess.MV6.utils.GetPopularSearchQueries();
			MV6DataContext dc = new MV6DataContext();

			// Special case handling -- Rearrange things for easier reading
			for (int i = 0; i < dt.Rows.Count; i++)
			{
				dt.Rows[i][0] = dt.Rows[i][0].ToString().Trim().ToLower();

				// Put any instances of "c#" at the beginning of the query due to problems with lots and lots of nearly-duplicate results
				if (dt.Rows[i][0].ToString().Contains("c#"))
					dt.Rows[i][0] = "c# " + dt.Rows[i][0].ToString().Replace("c#", "");

				// Shorten any instances of multiple consecutive spaces to a single space
				while (dt.Rows[i][0].ToString().Contains("  "))
					dt.Rows[i][0] = dt.Rows[i][0].ToString().Replace("  ", " ");
			}

			// Filter out the ones I'm currently tracking
			foreach (DataRow dr in dt.Rows)
			{
				if (dr[0] == null || string.IsNullOrEmpty(dr[0].ToString()))
					continue;

				string str = dr[0].ToString().ToLower().Trim();
				if ((from s in dc.SearchStatus
					 where s.Query.Contains(str)
					 orderby s.Query
					 select s)
						.Count() == 0)
					results.Add(str);
			}

			// Filter out the ones I'm currently tracking (Backwards filter)
			foreach (SearchStatus status in from status2 in dc.SearchStatus select status2)
				foreach (string result in results)
					if (!status.Query.ToLower().Contains(result) && !results2.Contains(result))
						results2.Add(result);

			// Filter out duplicates, and lines that are nearly duplicate, but not quite
			results = results2.ToList().FilterByDuplicateWords(7);
			results.Sort();

			// Build final report section
			string returnstr = "Suggested SearchStatuses: \r\n";
			foreach (string result in results)
				returnstr += "  " + result + "\r\n";
			dc.Dispose();
			UpdateResults("Suggested " + results.Count().ToString() + " SearchStatuses", false);
			return returnstr + "\r\n\r\n";
		}
		/// <summary>Builds a list of errors that have ocurred over the past 24 hours and provides some information about them.</summary>
		/// <returns>List of errors and error statistics</returns>
		private string GetErrors()
		{
			using (MV6DataContext dc = new MV6DataContext())
			{
				var errors = (from e in dc.Errors
							  where e.datetime >= (DateTime.Now.AddDays(-1))
							  orderby e.ID descending
							  select e);
				string returnstr = "Error Report: \r\n" +
					"  Total Errors: " + errors.Count().ToString() + "\r\n" +
					"  Critical Errors: " + errors.Where(p => p.Severity == 1).Count().ToString() + "\r\n" +
					"  Important Errors: " + errors.Where(p => p.Severity == 2).Count().ToString() + "\r\n" +
					"  Other Errors: " + errors.Where(p => p.Severity > 2).Count().ToString() + "\r\n";

				if (errors.Count() > 0)
				{
					returnstr += "Top 50 errors: \r\n";
					foreach (Error error in errors.Take(50))
					{
						string ex = error.Title;
						if (string.IsNullOrEmpty(ex))
							continue;
						if (ex.Length > 100)
							ex = ex.Substring(0, 100);
						returnstr += "  " + ex + "\r\n";
					}
				}
				UpdateResults("Reported on " + errors.Count().ToString() + " error(s)", false);
				return returnstr;
			}
		}

		/// <summary>Builds a list of broken IMG tags</summary>
		/// <returns>Report on broken IMG tags</returns>
		private string BuildListOfBrokenImgTags()
		{
			string report = "";
			int numAffected = 0;
			foreach (Post post in from p in this.dcMV6.Posts orderby p.ID select p)
			{
				report += post.ID.ToString() + ": " + post.Title + "\r\n";
				foreach (string link in KC.Business.Net.Web.BuildListOfImgTags(post.Body, KC.Business.Net.Web.HyperlinkOption.Broken))
				{
					report += " - " + link + "\r\n";
					numAffected++;
				}
			}
			UpdateResults(numAffected.ToString() + " broken images detected.",false);
			return report;
		}
		/// <summary>Uhh... sends mail?</summary>
		/// <param name="body">Body of message to send to myself</param>
		private static void Sendmail(string body)
		{
			if (string.IsNullOrEmpty(body))
				throw new ArgumentNullException("body", "Cannot send null body via email");

			bool result = KC.Business.Net.Mail.SendMail("kevin@kconnolly.net", "Daily Report for " + DateTime.Now.ToString("MM-dd-yyyy"), body);
			if (!result) KC.Logging.Logger.Write("META", "Error sending mail", "A result of false came back from Sendmail()", Logging.Logger.Severity.Error);
		}

		#endregion Implementation
	}
}
